#include "persistentstorage.h"

#include "plan.h"
#include <QSqlDatabase>
#include <QSqlError>
#include <QDebug>
#include <stdlib.h>

PersistentStorage::PersistentStorage()
{
}

QString PersistentStorage::connectionString()
{
  QString home = getenv("HOME");
  QString xdg_config_home = getenv("XDG_CONFIG_HOME");
  if(xdg_config_home.isEmpty())
    xdg_config_home = home + "/.config";
  return xdg_config_home + "/planner.db";
}

void PersistentStorage::connect()
{
  QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
  QString cnctstr = connectionString();
  db.setDatabaseName(cnctstr);
  if(!db.open())
    qWarning() << db.lastError().nativeErrorCode();
  if(!db.tables().contains("Plan")) {
    QSqlQuery q;
    q.exec("CREATE TABLE Plan (id INTEGER PRIMARY KEY ASC AUTOINCREMENT, title TEXT NOT NULL, date INTEGER NOT NULL, description TEXT NOT NULL, state INTEGER NOT NULL)");
  }
}

Plan &PersistentStorage::addPlan(Plan &p)
{
  QSqlQuery q;
  bool hasError;
  QSqlError err = execAddPlan(q, p, hasError);
  if(hasError)
    qWarning() << err.driverText() << err.databaseText() << err.nativeErrorCode();
  return p;
}

void PersistentStorage::removePlan(Plan &p)
{
  QSqlQuery q;
  QSqlError err;
  bool hasError;
  err = execRemovePlan(q, p, hasError);
  if(hasError)
    qWarning() << err.driverText() << err.databaseText() << err.nativeErrorCode();
}

void PersistentStorage::updatePlan(Plan &p)
{
  QSqlQuery q;
  QSqlError err;
  bool hasError;
  err = execUpdatePlan(q, p, hasError);
  if(hasError)
    qWarning() << err.driverText() << err.databaseText() << err.nativeErrorCode();
}

QList<Plan *> PersistentStorage::findAll()
{
  QSqlQuery q;
  QList<Plan *> plans;
  QSqlError err;
  bool hasError;
  err = execFindAll(q, hasError);
  if(hasError)
    qWarning() << err.driverText() << err.databaseText() << err.nativeErrorCode();
  while(q.next()) {
    Plan *p = new Plan();
    p->setId(q.value(0).toInt(NULL));
    p->setTitle(q.value(1).toString());
    p->setDate(QDateTime::fromMSecsSinceEpoch(q.value(2).toLongLong()));
    p->setDescription(q.value(3).toString());
    p->setState(q.value(4).toInt(NULL));
    plans.append(p);
  }

  return plans;
}

QSqlError PersistentStorage::execAddPlan(QSqlQuery &q, Plan &p, bool &hasError)
{
  q.prepare("INSERT INTO Plan (title, date, description, state) VALUES (:title, :date, :desc, :state)");
  q.bindValue(":title", p.title());
  q.bindValue(":date", p.date().toMSecsSinceEpoch());
  q.bindValue(":desc", p.description());
  q.bindValue(":state", (int)p.state());
  if(!q.exec()) {
    hasError = true;
    return q.lastError();
  }
  p.setId(q.lastInsertId().toInt(NULL));
  hasError = false;
  return QSqlError();
}

QSqlError PersistentStorage::execUpdatePlan(QSqlQuery &q, Plan &p, bool &hasError)
{
  q.prepare("UPDATE Plan SET title = :title, date = :date, description = :desc, state = :state WHERE id = :id");
  q.bindValue(":title", p.title());
  q.bindValue(":date", p.date().toMSecsSinceEpoch());
  q.bindValue(":desc", p.description());
  q.bindValue(":state", (int)p.state());
  q.bindValue(":id", p.id());
  if(!q.exec()) {
    hasError = true;
    return q.lastError();
  }
  hasError = false;
  return QSqlError();
}

QSqlError PersistentStorage::execRemovePlan(QSqlQuery &q, Plan &p, bool &hasError)
{
  q.prepare("DELETE FROM Plan WHERE id = :id");
  q.bindValue(":id", p.id());
  if(!q.exec()) {
    hasError = true;
    return q.lastError();
  }
  hasError = false;
  return QSqlError();
}

QSqlError PersistentStorage::execFindAll(QSqlQuery &q, bool &hasError)
{
  if(!q.exec("SELECT * FROM Plan")){
    hasError = true;
    return q.lastError();
  }
  hasError = false;
  return QSqlError();
}
